/******************************************************
Compile : gcc -O3 -o circuit circuit.c sim.c utils.c solver.c -lm
Usage : ./circuit input
******************************************************/

#include "solver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct circuit {
	int n, m, s; /* n: nubmer of input variables; m: number of rows in the truth table; s: number of helper variables */
	int *truthtable;
};

void print_help ()
{
	printf ("Usage		: ./circuit inputfile\n");
	printf ("		 (./circuit input)\n\n");
}

void find_network (struct circuit *circuit)
{
	int i, j, k, m;
	int N, M, L;

	N = circuit->n + circuit->s + 1;
	M = circuit->m;
	L = 3;

	int pathway[L][N];
	int S[L][N]; /* state variable */
	int g[N][N], r[N][N]; /* network variable ; g[i][j]/r[i][j] edge from j to i */

	for (i = 0; i < N; i++)
	{
		for (j = 0; j < N; j++)
		{
			g[i][j] = i * N + j;
			r[i][j] = N * N + i * N + j;
		}
	}

	solver *s;
	bool st;

	s = solver_new ();

	m = 2 * N * N;

	for (k = 0; k < M; k++)
	{

		for (i = 0; i < L; i++)
		{
			for (j = 0; j < N; j++)
			{
				S[i][j] = m + i * N + j;
				pathway[i][j] = -1;
			}
		}

		m = S[L - 1][N - 1];

		/* restriction of the strong inhibition rules */
		m = sim_model (N, L, pathway, S, g, r, s, m);

		for (i = 0; i < circuit->n; i++)
		{
			pathway[0][i] = circuit->truthtable[k * (circuit->n + 1) + i];
		}
		pathway[L - 1][N - 1] = circuit->truthtable[k * (circuit->n + 1) + i];

		for (i = circuit->n; i < N; i++)
		{
			pathway[0][i] = 1;
		}
		pathway[0][N - 1] = 1;

		/* setup the known values in the pathway */
		set_pathway (N, L, pathway, S, s);
	}

	st = solver_simplify (s);
	if (st == true)
		st = solver_solve (s,0,0);

	if (st == true)
	{
		for (i = 0; i < N; i++)
		{
			for (j = 0; j < N; j++)
			{
				if (s->model.ptr[r[i][j]] == l_True)
					printf ("r ");
				else if (s->model.ptr[g[i][j]] == l_True)
					printf ("g ");
				else
					printf ("n ");
			}
			printf ("\n");
		}
	}
	else
	{
		printf ("No solution when L = %d!\n", L);
	}

	solver_delete (s);
}

void read_inputfile (int argc, char *argv[], struct circuit *circuit)
{
	FILE *fp;
	char buf[256];
	int i, j;

	fp = fopen (argv[1], "r");
	fscanf (fp, "%d %d %d", &circuit->n, &circuit->m, &circuit->s);
	fgets (buf, 256, fp);

	circuit->truthtable = calloc (circuit->m * (circuit->n + 1), sizeof (int));

	for (i = 0; i < circuit->m; i++)
	{
		for (j = 0; j <= circuit->n; j++)
		{
			fscanf (fp, "%d", circuit->truthtable + i * (circuit->n + 1) + j);
		}
		fgets (buf, 256, fp);
	}

	fclose (fp);
}

int main (int argc, char *argv[])
{
	int i;
	struct circuit circuit;

	if (argc == 1)
	{
		print_help ();
		exit (0);
	}

	read_inputfile (argc, argv, &circuit);

	find_network (&circuit);
}
